package cn.iocoder.yudao.module.erp.service.product;

import cn.hutool.core.collection.CollUtil;
import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
import cn.iocoder.yudao.framework.common.exception.ServiceException;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.util.collection.MapUtils;
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
import cn.iocoder.yudao.module.erp.controller.admin.product.vo.product.ErpProductPageReqVO;
import cn.iocoder.yudao.module.erp.controller.admin.product.vo.product.ErpProductRespVO;
import cn.iocoder.yudao.module.erp.controller.admin.product.vo.product.ProductSaveReqVO;
import cn.iocoder.yudao.module.erp.controller.admin.product.vo.productPrice.ProductPriceSaveReqVO;
import cn.iocoder.yudao.module.erp.controller.app.product.vo.product.ErpAppProductPageReqVO;
import cn.iocoder.yudao.module.erp.controller.app.product.vo.product.ErpAppProductRespVO;
import cn.iocoder.yudao.module.erp.dal.dataobject.product.ErpProductCategoryDO;
import cn.iocoder.yudao.module.erp.dal.dataobject.product.ErpProductDO;
import cn.iocoder.yudao.module.erp.dal.dataobject.product.ErpProductPriceDO;
import cn.iocoder.yudao.module.erp.dal.dataobject.product.ErpProductUnitDO;
import cn.iocoder.yudao.module.erp.dal.dataobject.purchase.ErpPurchaseApplyOrderItemDO;
import cn.iocoder.yudao.module.erp.dal.mysql.product.ErpProductMapper;
import cn.iocoder.yudao.module.erp.dal.mysql.product.ErpProductPriceMapper;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import org.springframework.stereotype.Service;
import org.springframework.validation.annotation.Validated;

import javax.annotation.Resource;
import javax.management.ServiceNotFoundException;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;

import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.*;
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList;
import static cn.iocoder.yudao.module.erp.enums.ErrorCodeConstants.PRODUCT_NOT_ENABLE;
import static cn.iocoder.yudao.module.erp.enums.ErrorCodeConstants.PRODUCT_NOT_EXISTS;

/**
 * ERP 产品 Service 实现类
 *
 * @author 芋道源码
 */
@Service
@Validated
public class ErpProductServiceImpl implements ErpProductService {

    @Resource
    private ErpProductMapper productMapper;
    @Resource
    private ErpProductPriceMapper productPriceMapper;
    @Resource
    private ErpProductCategoryService productCategoryService;
    @Resource
    private ErpProductUnitService productUnitService;

    @Override
    public Long createProduct(ProductSaveReqVO createReqVO) {
        //产品名称不能重复
        Long l = productMapper.selectCount(new QueryWrapper<ErpProductDO>().eq("name", createReqVO.getName()));
        if (l > 0) {
            throw new ServiceException("产品名称不能重复");
        }

        l = productMapper.selectCount(new QueryWrapper<ErpProductDO>().eq("bar_code", createReqVO.getBarCode()));
        if (l > 0) {
            throw new ServiceException("产品条码不能重复");
        }
        // 插入
        ErpProductDO product = BeanUtils.toBean(createReqVO, ErpProductDO.class);
        productMapper.insert(product);
        // 返回
        return product.getId();
    }

    @Override
    public void updateProduct(ProductSaveReqVO updateReqVO) {
        // TODO 芋艿：校验分类
        // 校验存在
     //   validateProductExists(updateReqVO.getId());
        ErpProductDO product = productMapper.selectById(updateReqVO.getId());
        if(product == null){
            throw exception(PRODUCT_NOT_EXISTS);
        }
        Long l = 0L;
        if(!product.getName().equals(updateReqVO.getName())){
            l = productMapper.selectCount(new QueryWrapper<ErpProductDO>().eq("name", updateReqVO.getName()));
            if (l > 0) {
                throw new ServiceException("产品名称不能重复");
            }
        }
        if(!product.getBarCode().equals(updateReqVO.getBarCode())){
            l = productMapper.selectCount(new QueryWrapper<ErpProductDO>().eq("bar_code", updateReqVO.getBarCode()));
            if (l > 0) {
                throw new ServiceException("产品条码不能重复");
            }
        }
        // 更新
        ErpProductDO updateObj = BeanUtils.toBean(updateReqVO, ErpProductDO.class);
        productMapper.updateById(updateObj);
    }

    @Override
    public void updateProductPrice(ProductPriceSaveReqVO updateReqVO) {
        // 校验存在
        validateProductExists(updateReqVO.getId());
        // 校验时间是否有重叠
        List<ErpProductPriceDO> list = validProductPriceList(updateReqVO);

        updatePriceList(updateReqVO.getId(), list);

    }

    List<ErpProductPriceDO> validProductPriceList (ProductPriceSaveReqVO updateReqVO) {
        List<ErpProductPriceDO> erpProductPriceDOS = convertList(updateReqVO.getProductPriceList(), o -> BeanUtils.toBean(o, ErpProductPriceDO.class, DO->{
            DO.setProductId(updateReqVO.getId());
        }));

        //校验erpProductPriceDOS中的开始结束时间是否有重叠的情况
        checkOverlapping(erpProductPriceDOS);

        return erpProductPriceDOS;
    }


//    public static void checkOverlapping(List<ErpProductPriceDO> erpProductPriceDOS) {
//        for (int i = 0; i < erpProductPriceDOS.size(); i++) {
//            for (int j = i + 1; j < erpProductPriceDOS.size(); j++) {
//                ErpProductPriceDO productPriceDO1 = erpProductPriceDOS.get(i);
//                ErpProductPriceDO productPriceDO2 = erpProductPriceDOS.get(j);
//
//                if (isOverlapping(productPriceDO1, productPriceDO2)) {
//                    throw new ServiceException("价格时间段有重叠");
//                }
//            }
//        }
//    }
//
//    private static boolean isOverlapping(ErpProductPriceDO productPriceDO1, ErpProductPriceDO productPriceDO2) {
//        return productPriceDO1.getStartTime().isBefore(productPriceDO2.getEndTime()) &&
//                productPriceDO1.getEndTime().isAfter(productPriceDO2.getStartTime()) &&
//                !productPriceDO1.getStartTime().equals(productPriceDO2.getEndTime()) &&
//                !productPriceDO1.getEndTime().equals(productPriceDO2.getStartTime());
//    }

    public static void checkOverlapping(List<ErpProductPriceDO> erpProductPriceDOS) {
        // 先按开始时间排序，这样只需要比较相邻的时间段
        List<ErpProductPriceDO> sortedList = erpProductPriceDOS.stream()
                .sorted(Comparator.comparing(ErpProductPriceDO::getStartTime))
                .collect(Collectors.toList());

        for (int i = 0; i < sortedList.size() - 1; i++) {
            ErpProductPriceDO current = sortedList.get(i);
            ErpProductPriceDO next = sortedList.get(i + 1);

            if (isOverlapping(current, next)) {
                throw new ServiceException("价格时间段有重叠");
            }
        }
    }

    private static boolean isOverlapping(ErpProductPriceDO productPriceDO1, ErpProductPriceDO productPriceDO2) {
        // 校验时间段是否有重叠，包括时间相等的情况
        return !productPriceDO1.getEndTime().isBefore(productPriceDO2.getStartTime()) &&
                !productPriceDO2.getEndTime().isBefore(productPriceDO1.getStartTime());
    }


    private void updatePriceList(Long id, List<ErpProductPriceDO> newList) {
        // 第一步，对比新老数据，获得添加、修改、删除的列表
        List<ErpProductPriceDO> oldList = this.getProductPrice(id);
        List<List<ErpProductPriceDO>> diffList = diffList(oldList, newList, // id 不同，就认为是不同的记录
                (oldVal, newVal) -> oldVal.getId().equals(newVal.getId()));

        // 第二步，批量添加、修改、删除
        if (CollUtil.isNotEmpty(diffList.get(0))) {
            diffList.get(0).forEach(o -> o.setProductId(id));
            productPriceMapper.insertBatch(diffList.get(0));
        }
        if (CollUtil.isNotEmpty(diffList.get(1))) {
            productPriceMapper.updateBatch(diffList.get(1));
        }
        if (CollUtil.isNotEmpty(diffList.get(2))) {
            productPriceMapper.deleteBatchIds(convertList(diffList.get(2), ErpProductPriceDO::getId));
        }
    }

    @Override
    public void deleteProduct(Long id) {
        // 校验存在
        validateProductExists(id);
        // 删除
        productMapper.deleteById(id);
    }

    @Override
    public List<ErpProductDO> validProductList(Collection<Long> ids) {
        if (CollUtil.isEmpty(ids)) {
            return Collections.emptyList();
        }
        List<ErpProductDO> list = productMapper.selectBatchIds(ids);
        Map<Long, ErpProductDO> productMap = convertMap(list, ErpProductDO::getId);
        for (Long id : ids) {
            ErpProductDO product = productMap.get(id);
            if (productMap.get(id) == null) {
                throw exception(PRODUCT_NOT_EXISTS);
            }
            if (CommonStatusEnum.isDisable(product.getStatus())) {
                throw exception(PRODUCT_NOT_ENABLE, product.getName());
            }
        }
        return list;
    }

    private void validateProductExists(Long id) {
        if (productMapper.selectById(id) == null) {
            throw exception(PRODUCT_NOT_EXISTS);
        }
    }

    @Override
    public ErpProductDO getProduct(Long id) {
        return productMapper.selectById(id);
    }

    @Override
    public List<ErpProductRespVO> getProductVOListByStatus(Integer status) {
        List<ErpProductDO> list = productMapper.selectListByStatus(status);
        return buildProductVOList(list);
    }

    @Override
    public List<ErpProductRespVO> getProductVOList(Collection<Long> ids) {
        if (CollUtil.isEmpty(ids)) {
            return Collections.emptyList();
        }
        List<ErpProductDO> list = productMapper.selectBatchIds(ids);
        return buildProductVOList(list);
    }

    @Override
    public PageResult<ErpProductRespVO> getProductVOPage(ErpProductPageReqVO pageReqVO) {
        PageResult<ErpProductDO> pageResult = productMapper.selectPage(pageReqVO);
        return new PageResult<>(buildProductVOList(pageResult.getList()), pageResult.getTotal());
    }

    private List<ErpProductRespVO> buildProductVOList(List<ErpProductDO> list) {
        if (CollUtil.isEmpty(list)) {
            return Collections.emptyList();
        }
        Map<Long, ErpProductCategoryDO> categoryMap = productCategoryService.getProductCategoryMap(
                convertSet(list, ErpProductDO::getCategoryId));
        Map<Long, ErpProductCategoryDO> parentCategoryMap = productCategoryService.getProductCategoryMap(
                convertSet(list, ErpProductDO::getParentCategoryId));
        Map<Long, ErpProductUnitDO> unitMap = productUnitService.getProductUnitMap(
                convertSet(list, ErpProductDO::getUnitId));

        //查询产品价格表，根据当前时间查询
        List<ErpProductPriceDO> erpProductPriceDOS = productPriceMapper.selectList(new LambdaQueryWrapper<ErpProductPriceDO>()
                .le(ErpProductPriceDO::getStartTime, LocalDateTime.now())
                .ge(ErpProductPriceDO::getEndTime, LocalDateTime.now())
        );
        //转为产品id为key的map
        Map<Long, ErpProductPriceDO> erpProductPriceDOMap = erpProductPriceDOS.stream().collect(Collectors.toMap(ErpProductPriceDO::getProductId, o -> o));

        return BeanUtils.toBean(list, ErpProductRespVO.class, product -> {
            if(product.getParentCategoryId() != null){
                MapUtils.findAndThen(parentCategoryMap, product.getParentCategoryId(),
                        category -> product.setParentCategoryName(category.getName()));
            }
            if(product.getCategoryId() != null){
            MapUtils.findAndThen(categoryMap, product.getCategoryId(),
                    category -> product.setCategoryName(category.getName()));
            }
            MapUtils.findAndThen(unitMap, product.getUnitId(),
                    unit -> product.setUnitName(unit.getName()));

//            MapUtils.findAndThen(erpProductPriceDOMap, product.getId(),
//                    priceDO -> product.setProductPrice(priceDO.getPrice()));
            product.setProductPrice(erpProductPriceDOMap.get(product.getId()) != null ? erpProductPriceDOMap.get(product.getId()).getPrice() : new BigDecimal("0"));

        });
    }

    @Override
    public Long getProductCountByCategoryId(Long categoryId) {
        return productMapper.selectCountByCategoryId(categoryId);
    }

    @Override
    public Long getProductCountByUnitId(Long unitId) {
        return productMapper.selectCountByUnitId(unitId);
    }

    @Override
    public List<ErpProductPriceDO> getProductPrice(Long productId) {
        return productPriceMapper.selectList(new LambdaQueryWrapper<ErpProductPriceDO>()
                .eq(ErpProductPriceDO::getProductId, productId));
    }


    public ErpProductPriceDO getProductPriceByNow(Long productId) {
        List<ErpProductPriceDO> erpProductPriceDOS = productPriceMapper.selectList(new LambdaQueryWrapper<ErpProductPriceDO>()
                .eq(ErpProductPriceDO::getProductId, productId)
                .le(ErpProductPriceDO::getStartTime, LocalDateTime.now())
                .ge(ErpProductPriceDO::getEndTime, LocalDateTime.now())
        );
        if(erpProductPriceDOS.size() > 1){
            throw new ServiceException("存在多个价格时间段");
        }

        return erpProductPriceDOS.get(0);
    }


    @Override
    public PageResult<ErpAppProductRespVO> getAppProductVOPage(ErpAppProductPageReqVO pageReqVO) {
        PageResult<ErpProductDO> pageResult = productMapper.selectAppPage(pageReqVO);
        return new PageResult<>(buildAppProductVOList(pageResult.getList()), pageResult.getTotal());
    }

    @Override
    public ErpAppProductRespVO getAppProduct(Long id) {
        ErpProductDO erpProductDO = productMapper.selectById(id);
        if (erpProductDO == null) {
            return null;
        }
        List<ErpProductDO> list = new ArrayList<>();
        list.add(erpProductDO);
        return buildAppProductVOList(list).get(0);
    }

    private List<ErpAppProductRespVO> buildAppProductVOList(List<ErpProductDO> list) {
        if (CollUtil.isEmpty(list)) {
            return Collections.emptyList();
        }
        Map<Long, ErpProductCategoryDO> categoryMap = productCategoryService.getProductCategoryMap(
                convertSet(list, ErpProductDO::getCategoryId));
        Map<Long, ErpProductUnitDO> unitMap = productUnitService.getProductUnitMap(
                convertSet(list, ErpProductDO::getUnitId));
        Map<Long, ErpProductCategoryDO> parentCategoryMap = productCategoryService.getProductCategoryMap(
                convertSet(list, ErpProductDO::getParentCategoryId));
        return BeanUtils.toBean(list, ErpAppProductRespVO.class, product -> {
            if(product.getParentCategoryId() != null) {
                MapUtils.findAndThen(parentCategoryMap, product.getParentCategoryId(),
                        category -> product.setParentCategoryName(category.getName()));
            }
            if(product.getCategoryId() != null) {
                MapUtils.findAndThen(categoryMap, product.getCategoryId(),
                        category -> product.setCategoryName(category.getName()));
            }
            MapUtils.findAndThen(unitMap, product.getUnitId(),
                    unit -> product.setUnitName(unit.getName()));
        });
    }

}
